跳到主要内容

WSL 高 CPU 异常排查

1、问题现象

某日打开 VSCode + WSL 开发环境后,即使没有运行任何程序, CPU 使用率长期维持在 80% 以上,风扇全速转动。

观察到:

  • Windows 任务管理器中:

    vmmemWSL.exe 占用 70%+ CPU,2.5GB 内存
  • 未启动 Docker、VMware,仅打开 WSL。

  • 进入 WSL 内部后使用 top,发现:

    top - 09:04:47 up 1 min,  1 user,  load average: 9.98, 3.12, 1.09
    %Cpu(s): 3.1 us, 75.0 sy, 0.0 ni, 20.7 id
    ...
    PID USER %CPU COMMAND
    683 root 1197 rg
    622 root 22 node
    575 root 15 node

    🔥 rg(ripgrep)单个进程占用 1197% CPU(约 12 核满载)。


2、初步判断:罪魁祸首 vmmemWSL 并非“真凶”

vmmemWSL 只是 WSL 虚拟机的“容器”, 它本身不执行代码,只是承载 Linux 子系统。因此,当 vmmemWSL 占用高时,真正的原因一定是 WSL 内部进程异常

进一步确认:

wsl --list --verbose

输出:

  NAME              STATE           VERSION
* Ubuntu Running 2
docker-desktop Stopped 2

说明仅有 Ubuntu 在运行。→ 问题出在 Ubuntu 内部进程


3、深入排查:找到真正的高占用源

执行:

top

发现:

PID 683 root  1197%  rg

rgripgrep,是一种超快的文件搜索工具。通常情况下,VSCode 会在后台使用它进行:

  • 全局搜索;
  • 文件索引;
  • 快速跳转(Ctrl + P)。

由此可推断: 👉 这是 VSCode Remote - WSL 自动触发的全盘索引。


4、原因分析:误在根目录 / 打开 VSCode

当我打开 WSL 时,执行了:

code /

这看似无害,但实际上 VSCode 会:

  1. 调用 ripgrep 从根目录 / 开始递归扫描;
  2. 扫描 /mnt/c, /mnt/d(即整个 Windows 文件系统);
  3. 递归进入 /proc, /sys, /usr, /lib 等系统目录;
  4. 导致 ripgrep 无限读取上百万个文件。

结果:

  • 每个核心都在做 I/O;
  • vmmemWSL 长期满载;
  • 整机噪音、温度飙升。

5、解决过程

✅ 1️⃣ 终止异常进程

在 WSL 中执行:

sudo pkill -9 rg

CPU 立即恢复正常。


✅ 2️⃣ 修改 VSCode 配置,排除 /mnt/**

创建或编辑项目内的 .vscode/settings.json

{
"search.exclude": {
"/mnt/**": true,
"**/node_modules": true,
"**/.git": true
},
"files.watcherExclude": {
"/mnt/**": true,
"**/node_modules/**": true,
"**/.git/**": true
},
"search.maxResults": 10000,
"search.followSymlinks": false
}

💡 /mnt/** 是关键,避免 VSCode 扫描整个 Windows 文件系统。


✅ 3️⃣ 再次测试

重新打开 VSCode:

code /
  • 打开初期(1–2 秒):
    • rg 短暂占用 1200% CPU(初始化索引)
  • 之后:
    • CPU 降回 <5%
    • vmmemWSL 稳定在 1–2%

说明配置生效 ✅。


6、进一步优化建议

优化项配置说明
限制 ripgrep 线程"search.ripgrep.maxThreads": 4降低启动峰值 CPU
禁止符号索引"search.quickOpen.includeSymbols": false减少启动 I/O
限制 WSL 资源.wslconfig 中添加: [wsl2] processors=6 memory=6GB避免 runaway 占用
正确打开路径code /home/用户名/项目名永远不要打开 //mnt

7、最终状态与验证

时间点现象说明
打开 VSCode 0–2 秒CPU 1000%+索引初始化
3 秒后CPU 降至 <5%搜索停止
长期运行node 0–2%,vmmemWSL <5%稳定

Windows 任务管理器中:

vmmemWSL.exe 使用率 2%~5%,内存 1.5GB 左右

系统恢复安静、温度正常。


8、经验总结

分类错误操作正确做法
打开路径/ 下打开 VSCode打开具体项目目录
索引范围未排除 /mnt/**明确排除 Windows 挂载盘
占用排查只看 vmmemWSL进入 WSL 内部用 top 定位
快速恢复重启电脑sudo pkill -9 rg 即可

9、启示与经验

  1. vmmemWSL 是症状,不是原因。 真正的高负载往往来自 WSL 内部进程。
  2. VSCode Remote-WSL 极易误扫 /mnt 这是最常见的性能陷阱。
  3. 监控工具组合使用:
    • Windows:任务管理器定位整体;
    • Linux:top / htop / ps aux 精确找出源头。
  4. 善用配置文件隔离问题: .vscode/settings.json.wslconfig 都是控制性能的关键。

10、总结

这次排查过程虽然简单,但非常典型:

一个不经意的操作(在根目录打开 VSCode) → 触发了 ripgrep 无限扫描 → 造成了“vmmemWSL CPU 高占用”的假象。

最终通过:

  • top 精确定位;
  • pkill rg 临时止血;
  • .vscode/settings.json 永久屏蔽 /mnt; 成功解决。

11、附录:完整 .vscode/settings.json 模板

{
"search.exclude": {
"/mnt/**": true,
"**/node_modules": true,
"**/.git": true
},
"files.watcherExclude": {
"/mnt/**": true,
"**/node_modules/**": true,
"**/.git/**": true
},
"search.maxResults": 10000,
"search.followSymlinks": false,
"search.ripgrep.maxThreads": 4,
"search.quickOpen.includeSymbols": false
}

11.1、 "search.exclude": { "/mnt/**": true, "**/node_modules": true, "**/.git": true }

用途:控制「搜索视图」(Ctrl+Shift+F)和 Quick Open 的文件集合——被排除的目录不会被递归扫描,也不会出现在搜索结果中。 效果:大幅降低 ripgrep (rg) 的 I/O 与 CPU 消耗。

  • "/mnt/**": true
    • 含义:从工作区根目录开始,排除 /mnt 下所有层级的内容。
    • 要点:如果你把工作区根设为 /(即 code /),这条规则才能命中真正的系统 /mnt。 若工作区根是 /home/you/project,那么 /mnt/** 只会匹配到 ~/project/mnt/**不会匹配系统的 /mnt
    • 实践建议:你现在会在 / 打开,故该规则能精准避免扫描 Windows 盘(/mnt/c/mnt/d)。
  • "**/node_modules": true"**/.git": true
    • 含义:在任意层级排除 node_modules.git,两者体量大、文件多,是常见热点。

📌 注意:search.exclude 只影响搜索集合,不影响「文件监视」与「资源管理器可见性」。后两者看下面的 files.watcherExclude

11.2、 "files.watcherExclude": { "/mnt/**": true, "**/node_modules/**": true, "**/.git/**": true }

用途:告诉 VS Code 的文件系统监听器(watcher)不要订阅这些路径的变更事件效果:减少后台文件事件合并、队列、去抖动等 CPU 活动,降低内存占用与卡顿。

  • "/mnt/**": true
    • 在工作区根为 / 时,避免订阅整个 Windows 盘的文件变更事件(由此避免 “动一下 Windows 文件,WSL 里就忙起来”)。
  • "**/node_modules/**""**/.git/**"
    • 阻止对依赖仓库与 VCS 元数据的实时监听,降低频繁变更时的开销(例如 Git 操作、包管理器写入)。

⚠️ 误区澄清: files.watcherExclude 不影响搜索范围,也不影响你手动打开文件——仅仅是不再“盯着它们看”。


11.3、"search.maxResults": 10000

用途:限制一次搜索最多返回的匹配条目数(显示到 UI 中)。 效果:防止“关键词过热”导致结果爆表、UI 卡顿。

  • 性能层面它是“结果上限”,不是“扫描硬上限”。当匹配很稀疏时,rg 仍可能遍历大量文件后才达到 1 万条结果或遍历结束。
  • 配合 search.exclude 使用,整体 I/O 就能有效压缩。

用途:搜索时不跟随符号链接好处

  • 防止因为软链把搜索“带出项目外”或形成环路(常见:软链到 /mnt 或到上层目录)。
  • 减少扫描体积与系统调用。

取舍:如果你的项目刻意用软链组织源码(例如 monorepo 的某些布局),关闭跟随可能漏搜这些被软链包含的路径。此时可按需改为 true,但务必确保不会指到 /mnt


11.5、"search.ripgrep.maxThreads": 4

用途:限制 rg并发线程数好处:降低启动瞬间的 CPU 峰值(你之前看到 1200% 就是 rg 按“每核一线程”并行扫描)。

取舍

  • 线程越少,峰值更低、但搜索更慢
  • 一般 4~8 之间比较平衡;你的 8845HS 是 8C16T,设 4 已能明显抑制尖峰。

11.6、 "search.quickOpen.includeSymbols": false

用途:控制 Quick Open(Ctrl+P)是否**把符号(函数、类、变量)**也混入结果。 好处(设为 false)

  • 减少对语言服务(LSP/TS Server 等)的索引压力;
  • 避免为符号生成额外的背景扫描,降 CPU/内存。

体验变化

  • Ctrl+P 仅按文件名/路径模糊匹配;
  • 查找符号请改用 Ctrl+T 或语言自带的“转到符号”,更可控。

11.7 通配符与路径匹配要点(很重要)

  • **:任意多层目录;*:单层内任意名称;
  • / 开头的模式:锚定到工作区根,不是系统根;
  • 在 Remote-WSL:
    • 如果你打开的是 //mnt/** 就是系统 /mnt/**
    • 如果你打开的是 /home/you/project/mnt/** 只匹配 ~/project/mnt/**会屏蔽系统 /mnt
    • 全局屏蔽系统 /mnt 时,要么在 / 打开工作区(你现在就是),要么把同样的规则写进 Remote-WSL 的用户级设置~/.vscode-server/data/Machine/settings.json